/**
 * bsw_epoll.c
 * IO 多路复用 epoll 简单使用
 * 用于支撑 event 事件驱动模型
 * 
 * 竹影半墙
 * 2023.09
 */
#include <errno.h>
#include <unistd.h>
#include <sys/epoll.h>
#include "bsw_event.h"

static int epfd = -1;

#if 0
#endif
static int epoll_init(int size)
{
    epfd = epoll_create(size);
    return epfd > 0 ? 0 : errno;
}

static void epoll_close(void)
{
    if (epfd > 0)
        close(epfd);
    epfd = -1;
    return ;
}

static int epoll_adm(int op, int fd, uint32_t events, uint64_t u64)
{
    int ret;
    struct epoll_event ee;

    ee.data.u64 = u64;
    ee.events = events;
    ret = epoll_ctl(epfd, op, fd, &ee);
    if (bsw_unlikely(ret))
        return ret;
    return BSW_OK;
}

static int epoll_add(int fd, uint32_t events, uint64_t u64)
{
    return epoll_adm(EPOLL_CTL_ADD, fd, events, u64);
}

static int epoll_mod(int fd, uint32_t events, uint64_t u64)
{
    return epoll_adm(EPOLL_CTL_MOD, fd, events, u64);
}

static int epoll_del(fd)
{
    return epoll_adm(EPOLL_CTL_DEL, fd, 0, NULL);
}

static int epoll_enqueue(bsw_event_queue_s *q, int timeout_ms)
{
    int i, ew;
    struct epoll_event ee[1024];

    for (;;) {
        ew = epoll_wait(epfd, ee, bsw_arrays(ee), timeout_ms);
        if (BSW_SYSCALL_BAD==ew && errno==EINTR)
            continue;
        if (BSW_SYSCALL_BAD==ew || ew == 0)
            break;
        for (i = 0; i < ew; ++i) {
            bsw_event_enqueue_tail(ee[i].events, ee[i].data.u64, q);
        }
    }
    return ew;
}

#if 0
#endif
bsw_event_action_s bsw_event_action_epoll = {
    .add  = epoll_add,
    .enqueue = epoll_enqueue,
    .mod  = epoll_mod,
    .del  = epoll_del,
    .init = epoll_init,
    .close = epoll_close
};